function CPU() {
    const stack = [];
    const register = { a: 0, b: 0, c: 0, d: 0 }
    function readReg(name) {
        return register[name]
    }
    function writeReg(name, value) {
        register[name] = value
    }
    function popStack() {
        return stack.pop()
    }
    function writeStack(value) {
        stack.push(value)
    }
    return {
        stack,
        register,
        readReg,
        writeReg,
        popStack,
        writeStack,
    }
}
function Machine(cpu) {
    function exec(cmd) {
        fn = {
            'add': (a, b) => a + b,
            'sub': (a, b) => a - b,
            'mul': (a, b) => a * b,
            'div': (a, b) => Math.floor(a / b),
            'and': (a, b) => a & b,
            'or': (a, b) => a | b,
            'xor': (a, b) => a ^ b
        }
        var arithmetic_reg = /((add)|(sub)|(mul)|(div)|(and)|(xor)|(or))(a)?\s([a-d]|\d+)(,\s([a-d]))?/;
        if (/push\s(\d+)/.test(cmd)) {
            cpu.writeStack(+RegExp.$1);
        } else if (/push\s([a-d])/.test(cmd)) {
            cpu.writeStack(cpu.readReg(RegExp.$1))
        } else if (/^pop$/.test(cmd)) {
            cpu.popStack();
        } else if (/pop\s([a-d])/.test(cmd)) {
            cpu.writeReg(RegExp.$1, cpu.popStack());
        } else if (/^pushr$/.test(cmd)) {
            for (c of 'abcd') cpu.writeStack(cpu.readReg(c));
        } else if (/^pushrr$/.test(cmd)) {
            for (c of 'dcba') cpu.writeStack(cpu.readReg(c));
        } else if (/^popr$/.test(cmd)) {
            for (c of 'dcba') cpu.writeReg(c, cpu.popStack());
        } else if (/^poprr$/.test(cmd)) {
            for (c of 'abcd') cpu.writeReg(c, cpu.popStack());
        } else if (/mov\s(\d+|[a-d]),\s([a-d])/.test(cmd)) {
            var value = RegExp.$1;
            if (/[a-d]/.test(value)) value = cpu.readReg(value);
            cpu.writeReg(RegExp.$2, +value);
        } else if (arithmetic_reg.test(cmd)) {
            var op = cmd.split(' ')[0]
            var has_a = op.endsWith('a') ? true : false;
            if (has_a) op = op.slice(0, -1);
            var s = cmd.replace(/((add)|(sub)|(mul)|(div)|(and)|(xor)|(or))(a)?/, '').trim();
            var value = s.split(',')[0].trim();
            var target = (s.split(',')[1] || 'a').trim()
            if (has_a) cpu.writeStack(cpu.readReg('a'));
            var n = /[a-d]/.test(value) ? +cpu.readReg(value) : +value;
            var temp = cpu.popStack();
            for (var i = 0; i < n - 1; i++)temp = fn[op](temp, cpu.popStack());
            cpu.writeReg(target, temp);
        }
    }
    return { exec }
}


//test 
cpu = CPU();
machine = Machine(cpu);
machine.exec("push 25");
machine.exec("push 15");
machine.exec("push 10");
machine.exec("add 3");
machine.exec("push 22");
machine.exec("push 13");
machine.exec("push 75");
machine.exec("sub 3");
machine.exec("push 10");
machine.exec("push 5");
machine.exec("push 5");
machine.exec("push 5");
machine.exec("push 5");
machine.exec("mul 5");
machine.exec("push 5");
machine.exec("push 20");
machine.exec("push 5");
machine.exec("push 10000");
machine.exec("div 4");
machine.exec("push 25");
machine.exec("push 15");
machine.exec("push 10");
machine.exec("add 3");

machine.exec("push 17");
machine.exec("suba 2, b");

machine.exec("push 5");
machine.exec("mula 2, c");

machine.exec("pushr");
machine.exec("add 4");


//aaaaaaaaaaaaaaaaaaa
machine.exec("mov 15, a");
machine.exec("mov 22, b");
machine.exec("mov 2, c");

machine.exec("pushrr");
machine.exec("mul 2");
machine.exec("diva 2");

console.log(cpu)